home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 2000 April: Mac OS SDK / Dev.CD Apr 00 SDK1.toast / Development Kits / Mac OS / Open Transport 1.3 / Open Transport SDK / Open Tpt Client Developer / Samples / AppleTalk / ATPSample.cp < prev    next >
Encoding:
Text File  |  1998-04-30  |  21.5 KB  |  922 lines  |  [TEXT/MPS ]

  1. /*
  2.     File:        ATPSample.cp
  3.  
  4.     Contains:    Sample program for the ATP endpoint
  5.  
  6.     Copyright:    © 1993-1995 by Apple Computer, Inc., all rights reserved.
  7.  
  8. */
  9.  
  10. #ifndef __OPENTPTGLOBALNEW__
  11. #include <OpenTptGlobalNew.h>
  12. #endif
  13. #ifndef __OPENTPTAPPLETALK__
  14. #include <OpenTptAppleTalk.h>
  15. #endif
  16. #ifndef __ATALKSAMPLEUTILS__
  17. #include "ATalkSampleUtils.h"
  18. #endif
  19. #ifndef __STDIO__
  20. #include <stdio.h>
  21. #endif
  22. #ifndef __EVENTS__
  23. #include <Events.h>
  24. #endif
  25.  
  26. /*******************************************************************************
  27. ** Structures
  28. ********************************************************************************/
  29.  
  30. typedef struct TOutgoingRequest    TOutgoingRequest;
  31.  
  32. struct TOutgoingRequest
  33. {
  34.     TOutgoingRequest*    fLink;            // Link for list
  35.     TUnitRequest        fRequest;        // The actual Request;
  36.     Boolean                fHasReply;        // Flag for when reply comes in
  37. };
  38.  
  39. typedef struct TIncomingRequest    TIncomingRequest;
  40.  
  41. struct TIncomingRequest
  42. {
  43.     TIncomingRequest*    fLink;            // Link for list
  44.     TUnitRequest        fRequest;
  45.     TUnitReply            fReply;
  46.     DDPAddress            fAddr;            // Buffer for the address
  47.     Boolean                fNeedsReply;
  48.     Boolean                fIsXO;
  49.     Boolean                fNeedsMore;
  50. };
  51.  
  52. /*******************************************************************************
  53. ** GlobalVariables
  54. ********************************************************************************/
  55.  
  56. const char*        kRequestorName    = "ATPRequestor:WorkStation";
  57. const char*        kResponderName    = "ATPResponder:WorkStation";
  58. const size_t    kRequestSize    = 578 + 4;
  59. const size_t    kMaxRequests    = 4;
  60. const size_t    kMaxReplyBufLen    = (578 * 8) + 4;
  61. const size_t    kTestReplySize    = (578 * 8) + 4;
  62.  
  63. static char gRequestData[] =
  64. "    This is a test of the Emergency Broadcast System. \
  65.     This is only a test. If this had been an actual emergency, you would have been \
  66.     instructed where to tune in your area for more information.";
  67.  
  68. static UInt8     gReplyBuffer[kMaxReplyBufLen];
  69. static UInt8     gRequestBuffer[kRequestSize];
  70. //
  71. // Used for Bind, Resolve, and unbind
  72. //
  73. OTEventCode            gFunctionEvent;
  74. Boolean                gFunctionComplete;
  75. OSStatus            gFunctionErr;
  76. void*                gFunctionCookie;
  77. int                    gTestMode;
  78.  
  79. TOutgoingRequest*    gOutgoingRequestList;
  80. TIncomingRequest*    gIncomingRequestList;
  81. size_t                gOutgoingRequests;
  82. size_t                gIncomingRequests;
  83.  
  84.  
  85. long                 gReqSequence=0;
  86.  
  87. OTTimeStamp            gStartStamp;
  88. SInt32                gStartTicks;
  89. size_t                gTotalBytes;
  90. size_t                gDotCount    = 0;
  91. size_t                gLineCount    = 0;
  92. DDPAddress            gPeerAddress;
  93.  
  94. Boolean                gFlowControlled;
  95. Boolean                gIncomingRequestAvailable = false;
  96.  
  97. /*******************************************************************************
  98. ** DoStaticBind w/ Name Registration
  99. **        Static bind is where we let the endpoint choose our network
  100. **        address.
  101. **
  102. **        NOTE: no relationship between Static bind and async!
  103. ********************************************************************************/
  104.  
  105. OSStatus DoStaticBind(EndpointRef atpEp, const char* name)
  106. {
  107.     OSStatus        err = kOTNoError;
  108.     DDPNBPAddress    myAddress;            // To set up my address for the bind
  109.     DDPAddress        addr;                // To hold my address when we're done
  110.     //
  111.     // Initialize my address
  112.     //
  113.     myAddress.Init(0, 0, 0);        // Source address & type
  114.     //
  115.     // Create the TBind for the request, holding my address
  116.     //
  117.     TBind req;
  118.     //
  119.     // Set my name into the NBP address, and init the TBind with
  120.     // the address (SetNBPEntity returns the size of the address).
  121.     //
  122.     req.addr.buf    = (UInt8*)&myAddress;
  123.     req.addr.len    = myAddress.SetNBPEntity(name);
  124.     req.qlen        = 0;
  125.     //
  126.     // Create the TBind for the return information
  127.     //
  128.     TBind ret;
  129.     
  130.     ret.addr.buf    = (UInt8*)&addr;
  131.     ret.addr.maxlen    = sizeof(addr);
  132.  
  133.     fprintf(stderr, "Doing Bind\n");
  134.     //
  135.     // Try to bind
  136.     // 
  137.     gFunctionComplete = false;
  138.     
  139.     err = OTBind(atpEp, &req, &ret);
  140.     if ( err != kOTNoError )
  141.     {
  142.         fprintf(stderr, "OTBind: returned error %d\n", err);
  143.         return err;
  144.     }
  145.     //
  146.     // Wait for the bind to be complete
  147.     //
  148.     while ( !gFunctionComplete )
  149.         OTIdle();
  150.     
  151.     if ( gFunctionEvent != T_BINDCOMPLETE )
  152.     {
  153.         fprintf(stderr, "OTBind: completed with event %08lX instead of %08lX\n",
  154.                 gFunctionEvent, T_BINDCOMPLETE);
  155.         return kOTProtocolErr;
  156.     }
  157.     
  158.     if ( gFunctionErr != kOTNoError )
  159.     {
  160.         fprintf(stderr, "OTBind: completed with error %d\n", gFunctionErr);
  161.         return gFunctionErr;
  162.     }
  163.     fprintf(stderr, "Bound address = ");
  164.     ShowDDPAddress(&addr);
  165.     fprintf(stderr, "\n");
  166.     fprintf(stderr, "Bound queue len is %d\n", ret.qlen);
  167.  
  168.     fprintf(stderr, "After Bind, ");
  169.     ShowEndpointState(atpEp, "");
  170.  
  171.     return kOTNoError;
  172. }
  173.  
  174. /*******************************************************************************
  175. ** DoResolveAddr
  176. **        Find someone to talk to
  177. ********************************************************************************/
  178.  
  179. OSStatus DoResolveAddr(EndpointRef atpEp, const char* name, DDPAddress* peer)
  180. {
  181.     OSStatus    err = kOTNoError;
  182.     NBPAddress    peerAddress;
  183.     //
  184.     // Create the TBinds for the request and return information
  185.     // (Init sets the address and returns the size)
  186.     //
  187.     TBind req;
  188.  
  189.     req.addr.buf    = (UInt8*)&peerAddress;
  190.     req.addr.len    = peerAddress.Init(name);
  191.     req.qlen        = 0;
  192.     
  193.     TBind ret;
  194.  
  195.     ret.addr.buf    = (UInt8*)peer;
  196.     ret.addr.maxlen    = sizeof(DDPAddress);
  197.     //
  198.     // Try to resolve the address - wait 2 seconds
  199.     // 
  200.     gFunctionComplete = false;
  201.     err = OTResolveAddress(atpEp, &req, &ret, 2000);
  202.     if ( err != kOTNoError )
  203.     {
  204.         fprintf(stderr, "OTResolveAddress: returned error %d\n", err);
  205.         return err;
  206.     }
  207.     //
  208.     // Wait for something to happen
  209.     //
  210.     while ( !gFunctionComplete )
  211.         ;
  212.         
  213.     if ( gFunctionEvent != T_RESOLVEADDRCOMPLETE )
  214.     {
  215.         fprintf(stderr, "OTResolveAddress: completed with event %08lX instead of %08lX\n",
  216.                 gFunctionEvent, T_RESOLVEADDRCOMPLETE);
  217.         return kOTProtocolErr;
  218.     }
  219.         
  220.     if ( gFunctionErr != kOTNoError )
  221.     {
  222.         return gFunctionErr;
  223.     }
  224.     //
  225.     // Copy my peer's address into the global
  226.     //
  227.     fprintf(stderr, "Partner's address = ");
  228.     ShowDDPAddress(peer);
  229.     fprintf(stderr, "\n");
  230.     fflush(stderr);
  231.     return kOTNoError;
  232. }
  233.  
  234. /*******************************************************************************
  235. ** DoSendUReplies
  236. ********************************************************************************/
  237.  
  238. void DoSendUReplies(EndpointRef atpEp)
  239. {
  240.     OSStatus err;
  241.     
  242.     if ( gFlowControlled )
  243.         return;
  244.         
  245. /*    -------------------------------------------------------------------------
  246.     Now, let's send replies to any new incoming requests
  247.     ------------------------------------------------------------------------- */
  248.  
  249.     TIncomingRequest* next = gIncomingRequestList;
  250.     TIncomingRequest* prev = NULL;
  251.  
  252.     while ( next != NULL )
  253.     {
  254.         if ( next->fNeedsReply )
  255.         {
  256.             TUnitReply*    reply = &next->fReply;
  257.             reply->opt.len    = 0;
  258.             reply->udata.len    = sizeof(gReplyBuffer);
  259.             reply->udata.buf    = gReplyBuffer;
  260.             reply->sequence = next->fRequest.sequence;
  261.             OTMemset(reply->udata.buf, (int)next->fRequest.sequence, sizeof(gReplyBuffer));
  262.             
  263.             gFlowControlled = true;
  264.             
  265.             err = OTSndUReply(atpEp, reply, (OTFlags)0);
  266.             
  267.             if ( err != kOTFlowErr )
  268.                 gFlowControlled = false;
  269.             else
  270.                 return;
  271.  
  272.             if ( err == kOTNoError )
  273.             {
  274.                 gTotalBytes += sizeof(gReplyBuffer);
  275.                 next->fNeedsReply = false;
  276.                 gDotCount += 1;
  277.                 prev = next;
  278.                 next = next->fLink;
  279.             }
  280.             else
  281.             {
  282.                 fprintf(stderr, "OTSndUReply: returned error %d\n", err);
  283.                 //
  284.                 // If we got a memory-type error - we can recover.
  285.                 // Otherwise, we don't know what's going on, and
  286.                 // we'll just blow away the incoming request and
  287.                 // never answer it.
  288.                 //
  289.                 if ( err != kENOMEMErr && err != kENOSRErr )
  290.                 {
  291.                     if ( prev == NULL )
  292.                     {
  293.                         gIncomingRequestList = next->fLink;
  294.                     }
  295.                     else
  296.                     {
  297.                         prev->fLink = next->fLink;
  298.                     }
  299.                     gIncomingRequests -= 1;
  300.                     delete next;
  301.                 }
  302.             }
  303.         }
  304.         else
  305.         {
  306.             prev = next;
  307.             next = next->fLink;
  308.         }
  309.     }
  310. }
  311.  
  312. /*******************************************************************************
  313. ** DoReadURequests
  314. ********************************************************************************/
  315.  
  316. void DoReadURequests(EndpointRef atpEp)
  317. {
  318.     OTFlags    flags;
  319.     
  320.     while ( true )
  321.     {
  322.         TIncomingRequest* req = new TIncomingRequest;
  323.         
  324.         if ( req == NULL )
  325.         {
  326.             fprintf(stderr, "DoReadURequest: can't allocate incoming request structure\n");
  327.             //
  328.             // Since we didn't read to a kOTNoDataErr, set the flag back to indicate that
  329.             // we still have requests to read
  330.             //
  331.             gIncomingRequestAvailable = true;
  332.             return;
  333.         }
  334.     
  335.         req->fNeedsReply    = false;
  336.         
  337.         req->fRequest.addr.buf        = (UInt8*)&req->fAddr;
  338.         req->fRequest.addr.maxlen    = sizeof(req->fAddr);
  339.         req->fRequest.opt.maxlen    = 0;
  340.         req->fRequest.udata.buf        = gRequestBuffer;
  341.         req->fRequest.udata.maxlen    = sizeof(gRequestBuffer);
  342.  
  343.         OSStatus err = OTRcvURequest(atpEp, &req->fRequest, &flags);
  344.         
  345.         if ( err != kOTNoError )
  346.         {
  347.             delete req;
  348.             if ( err == kOTNoDataErr )
  349.             {
  350.                 gIncomingRequestAvailable = false;
  351.                 return;
  352.             }
  353.  
  354.             fprintf(stderr, "OTRcvURequest: returned error %d\n", err);
  355.             continue;
  356.         }
  357.         //
  358.         // We need to see if we already have an incoming request matching this.
  359.         //
  360.         TIncomingRequest*    next    = gIncomingRequestList;
  361.         //
  362.         // Find the incoming request on our list
  363.         //
  364.         while ( next != NULL )
  365.         {
  366.             if ( next->fRequest.sequence == req->fRequest.sequence )
  367.                 break;
  368.  
  369.             next = next->fLink;
  370.         }
  371.         //
  372.         // If next == NULL, then this is a brand new request
  373.         //
  374.         if ( next == NULL )
  375.         {
  376.             gTotalBytes += req->fRequest.udata.len;
  377.             req->fNeedsMore = (flags & T_MORE) ? true : false;
  378.             req->fIsXO        = (flags & T_ACKNOWLEDGED) ? true : false;
  379.             if ( !req->fNeedsMore )
  380.             {
  381.                 req->fNeedsReply = true;
  382.                 gIncomingRequests += 1;
  383.             }
  384.             req->fLink = gIncomingRequestList;
  385.             gIncomingRequestList = req;
  386.         }
  387.         else if ( !next->fNeedsMore )
  388.         {
  389.             fprintf(stderr, "OTRcvURequest: BAD BAD - received a duplicate request!!\n");
  390.             delete req;
  391.         }
  392.         else
  393.         {
  394.             gTotalBytes += req->fRequest.udata.len;
  395.             next->fNeedsMore = (flags & T_MORE) ? true : false;
  396.             if ( !(flags & T_MORE) )
  397.             {
  398.                 next->fNeedsReply = true;
  399.                 gIncomingRequests += 1;
  400.             }
  401.             delete req;
  402.         }
  403.     }
  404. }
  405.  
  406. /*******************************************************************************
  407. ** DoReadUReplies
  408. ********************************************************************************/
  409.  
  410. static void DoReadUReplies(EndpointRef atpEp)
  411. {
  412.  
  413.     OSStatus    err;
  414.     OTFlags        flags;
  415.     
  416.     while ( true )
  417.     {
  418.         TUnitReply    reply;
  419.         //
  420.         // For this sample, we don't really care what the 
  421.         // reply is, so we just read it into a global buffer.
  422.         //
  423.         reply.opt.maxlen    = 0;
  424.         reply.udata.maxlen    = sizeof(gReplyBuffer);
  425.         reply.udata.buf        = gReplyBuffer;
  426.         
  427.         err = OTRcvUReply(atpEp, &reply, &flags);
  428.         
  429.         if ( err != kOTNoError )
  430.         {
  431.             if ( err == kOTNoDataErr )
  432.                 return;
  433.             if ( err != kETIMEDOUTErr )
  434.             {
  435.                 fprintf(stderr, "\nOTRcvUReply: returned error %d\n", err);
  436.                 continue;
  437.             }
  438.         }
  439.         //
  440.         // We need to find the matching request
  441.         //
  442.         TOutgoingRequest*    prev    = NULL;
  443.         TOutgoingRequest*    next    = gOutgoingRequestList;
  444.         //
  445.         // Find the outgoing request on our list
  446.         //
  447.         while ( next != NULL )
  448.         {
  449.             if ( next->fRequest.sequence == reply.sequence )
  450.                 break;
  451.  
  452.             prev = next;
  453.             next = next->fLink;
  454.         }
  455.         if ( next == NULL )
  456.         {
  457.             fprintf(stderr, "\nOTRcvUReply: no matching request for reply\n");
  458.         }
  459.         //
  460.         // If the T_MORE flag is set, we won't remove the request from the list
  461.         // yet.  In real life, you need to obviously handle reading the "more"
  462.         // data somewhere rather than on top of the prior data.
  463.         //
  464.         gTotalBytes += reply.udata.len;
  465.         if ( !(flags & T_MORE) )
  466.         {
  467.             if ( prev == NULL )
  468.             {
  469.                 gOutgoingRequestList = next->fLink;
  470.             }
  471.             else
  472.             {
  473.                 prev->fLink = next->fLink;
  474.             }
  475.             delete next;
  476.             gOutgoingRequests -= 1;
  477.         }
  478.         
  479.     }
  480. }
  481.  
  482. /*******************************************************************************
  483. ** DoSendURequest
  484. ********************************************************************************/
  485.  
  486. void DoSendURequest(EndpointRef atpEp, int flag)
  487. {
  488.     OSStatus err = kOTNoError;
  489.     //
  490.     // If we have the maximum number of outstanding requests, or
  491.     // we are flow controlled - go away for now.
  492.     //
  493.     while ( true )
  494.     {
  495.         if ( gOutgoingRequests >= kMaxRequests || gFlowControlled )
  496.             return;
  497.             
  498.         TOutgoingRequest* req = new TOutgoingRequest;
  499.         
  500.         if ( req == NULL )
  501.         {
  502.             fprintf(stderr, "DoSendURequest: can't allocate outgoing request structure\n");
  503.             return;
  504.         }
  505.         
  506.         req->fHasReply            = false;
  507.         
  508.         req->fRequest.addr.buf    = (UInt8*)&gPeerAddress;
  509.         req->fRequest.addr.len    = kDDPAddressLength;
  510.         req->fRequest.opt.len    = 0;
  511.         req->fRequest.udata.buf    = (UInt8*)gRequestData;
  512.         req->fRequest.udata.len = sizeof(gRequestData);
  513.         req->fRequest.sequence    = ++gReqSequence;
  514.         //
  515.         // Throw it on the list of outgoing requests
  516.         //
  517.         req->fLink                = gOutgoingRequestList;
  518.         gOutgoingRequestList    = req;
  519.         
  520.         //
  521.         // Send the request
  522.         // We set the gFlowControlled flag now, because if we wait until we
  523.         // get the flow error, we might encounter a race condition where
  524.         // we set the flag after a new T_GODATA event clears it!
  525.         // This is not a problem when we do the sending inside the event handler,
  526.         // which is normally the case in a real application (because the event
  527.         // handler is never reentered).
  528.         //
  529.         gFlowControlled = true;
  530.         gOutgoingRequests += 1;
  531.         
  532.         err = OTSndURequest(atpEp, &req->fRequest, (OTFlags)flag);
  533.         
  534.         if ( err != kOTNoError )
  535.         {
  536.             gTotalBytes += sizeof(gRequestData);
  537.             gOutgoingRequests -= 1;
  538.             if ( err != kOTFlowErr )
  539.                 gFlowControlled = false;
  540.             fprintf(stderr, "OTSndURequest completed with error %d\n", err);
  541.             return;
  542.         }
  543.         gFlowControlled = false;
  544.         gDotCount += 1;
  545.     }
  546. }
  547.  
  548. /*******************************************************************************
  549. ** EventHandler
  550. ********************************************************************************/
  551.  
  552. pascal void EventHandler(void* contextPtr, OTEventCode event, OTResult result, void* cookie)
  553. {
  554.     switch ( event )
  555.     {
  556.         case T_REPLYCOMPLETE:
  557.         {
  558.             /*
  559.              * We have a reply that's done.  Find it on our list of incoming requests
  560.              * and remove it
  561.              */
  562.             TIncomingRequest*    prev    = NULL;
  563.             TIncomingRequest*    next    = gIncomingRequestList;
  564.         
  565.             while ( next != NULL )
  566.             {
  567.                 if ( &next->fReply == (TUnitReply*)cookie )
  568.                 {
  569.                     if ( prev == NULL )
  570.                     {
  571.                         gIncomingRequestList = next->fLink;
  572.                     }
  573.                     else
  574.                     {
  575.                         prev->fLink = next->fLink;
  576.                     }
  577.                     break;
  578.                 }
  579.                 prev = next;
  580.                 next = next->fLink;
  581.             }
  582.             if ( next == NULL )
  583.             {
  584.                 DebugStr("\pEventHandler: T_REPLYCOMPLETE event, but no matching request");
  585.             }
  586.             else
  587.             {
  588.                 if ( result != kOTNoError )
  589.                 {
  590.                     fprintf(stderr, "OTSndUReply: completed with error %d\n", result);
  591.                 }
  592.                 if ( prev == NULL )
  593.                     gIncomingRequestList = next->fLink;
  594.                 else
  595.                     prev->fLink = next->fLink;
  596.                 delete next;
  597.                 gIncomingRequests -= 1;
  598.             }
  599.             break;
  600.         }
  601.             
  602.         case T_BINDCOMPLETE:
  603.         case T_UNBINDCOMPLETE:
  604.         case T_RESOLVEADDRCOMPLETE:
  605.         {
  606.             gFunctionEvent        = event;
  607.             gFunctionErr        = (OSStatus)result;
  608.             gFunctionComplete    = true;
  609.             gFunctionCookie        = cookie;
  610.             break;
  611.         }
  612.             
  613.         case T_REPLY:
  614.         {
  615.             /*
  616.              * There are incoming replies - read them, then send more requests
  617.              */
  618.             DoReadUReplies((EndpointRef)contextPtr);
  619.             DoSendURequest((EndpointRef)contextPtr, gTestMode == 1 ? T_ACKNOWLEDGED : 0);
  620.             break;
  621.         }
  622.         
  623.         case T_REQUEST:
  624.         {
  625.             /*
  626.              * There are incoming requests - read them, then answer them
  627.              */
  628.             DoReadURequests((EndpointRef)contextPtr);
  629.             DoSendUReplies((EndpointRef)contextPtr);
  630.             break;
  631.         }
  632.         
  633.         case T_GODATA:
  634.         {
  635.             gFlowControlled = false;
  636.             switch ( gTestMode )
  637.             {
  638.                 case 1:
  639.                 case 2:
  640.                 {
  641.                     DoSendURequest((EndpointRef)contextPtr, gTestMode == 1 ? T_ACKNOWLEDGED : 0);
  642.                     break;
  643.                 }
  644.                 
  645.                 default:
  646.                 {
  647.                     DoReadURequests((EndpointRef)contextPtr);
  648.                     DoSendUReplies((EndpointRef)contextPtr);
  649.                     break;
  650.                 };
  651.             }
  652.             break;
  653.         }
  654.  
  655.         default:
  656.         {
  657.             DebugStr("\pEventHandler: Unexpected Event!");
  658.             break;
  659.         }
  660.     }
  661. }
  662.  
  663. /*******************************************************************************
  664. ** CreateEndpoint
  665. ********************************************************************************/
  666.  
  667. EndpointRef CreateEndpoint()
  668. {
  669.     EndpointRef    atpEp = kOTInvalidEndpointRef;
  670.     OSStatus    err = kOTNoError;
  671.  
  672.     do
  673.     {
  674.         //
  675.         // Now create an ATP endpoint synchronously
  676.         //
  677.         atpEp = OTOpenEndpoint(OTCreateConfiguration(kATPName), 0, NULL, &err);
  678.  
  679.         if ( atpEp == kOTInvalidEndpointRef || err != kOTNoError )
  680.         {
  681.             atpEp = kOTInvalidEndpointRef;
  682.             fprintf(stderr,"ERROR: OpenEndpoint(\"atp\") failed with %d\n", err);
  683.             break;
  684.         }
  685.         //
  686.         // Endpoint was created in synchronous mode, but it's always best to be safe
  687.         //
  688.         OTSetSynchronous(atpEp);
  689.         //
  690.         // Install notifier we're going to use for testing
  691.         //
  692.         err = OTInstallNotifier(atpEp, EventHandler, atpEp);
  693.         if ( err != kOTNoError )
  694.         {
  695.             fprintf(stderr, "ERROR: InstallNotifier() failed with %d\n", err);
  696.             break;
  697.         }
  698.         
  699.         ShowFullEndpointData(atpEp);
  700.         
  701.         return atpEp;
  702.         
  703.  
  704.     } while (false);
  705.     
  706.     if ( atpEp != kOTInvalidEndpointRef )
  707.         OTCloseProvider((ProviderRef)atpEp);
  708.     
  709.     return kOTInvalidEndpointRef;
  710. }
  711.  
  712. /*******************************************************************************
  713. ** DoTest
  714. ********************************************************************************/
  715.  
  716. void DoTest()
  717. {
  718.     long        waitSequence    = 0;
  719.     OSStatus    err                = kOTNoError;
  720.     Boolean        waitingToReply    = false;
  721.     EndpointRef    atpEp            = kOTInvalidEndpointRef;
  722.     
  723.     gOutgoingRequestList    = NULL;
  724.     gIncomingRequestList    = NULL;
  725.     
  726.     gOutgoingRequests            = 0;
  727.     gIncomingRequests            = 0;
  728.     gIncomingRequestAvailable    = false;
  729.  
  730.     gFlowControlled                = false;
  731.     
  732.      do
  733.     {
  734.     /*    -------------------------------------------------------------------------
  735.         Create endpoints.
  736.         ------------------------------------------------------------------------- */
  737.  
  738.         atpEp = CreateEndpoint();
  739.          if ( atpEp == kOTInvalidEndpointRef )
  740.          {
  741.              fprintf(stderr, "ATPSample: CreateEndpoint for ATP endpoint failed.\n", err);
  742.              break;
  743.          }
  744.  
  745.     /*    -------------------------------------------------------------------------
  746.         Get the test mode
  747.         ------------------------------------------------------------------------- */
  748.         
  749.         fprintf(stderr, "Enter 1=XO Requestor 2=ALO Requestor 3=Responder: ");
  750.         scanf("%x", &gTestMode);
  751.         fprintf(stderr, "Selected Mode is %d.\n", gTestMode);
  752.         
  753.         if ( gTestMode < 1 || gTestMode > 3 )
  754.             break;
  755.  
  756.     /*-------------------------------------------------------------------------
  757.         Bind endpoint.
  758.         ------------------------------------------------------------------------- */
  759.  
  760.         atpEp->SetAsynchronous();
  761.  
  762.         err = DoStaticBind(atpEp, gTestMode == 3 ? kResponderName : kRequestorName);
  763.         if ( err != kOTNoError )
  764.         {
  765.             fprintf(stderr, "ATPSample: bind of ATP endpoint failed (error %d).\n", err);
  766.             break;
  767.         }
  768.  
  769.     /*    -------------------------------------------------------------------------
  770.         Prepare to run - If we're the requestor, try to find the responder.
  771.         ------------------------------------------------------------------------- */
  772.  
  773.         if ( gTestMode == 1 || gTestMode == 2 )
  774.         {
  775.             OTTimeStamp    stamp;
  776.             Boolean        firstTime = true;
  777.             
  778.             OTGetTimeStamp(&stamp);
  779.             do
  780.             {
  781.                 err = DoResolveAddr(atpEp, kResponderName, &gPeerAddress);
  782.                 if ( err == kOTNoError )
  783.                     break;
  784.                 if ( firstTime )
  785.                 {
  786.                     firstTime = false;
  787.                     fprintf(stderr, "Waiting for Responder to come on-line.\n");
  788.                     fprintf(stderr, "Press mouse button to abort\n");
  789.                 }
  790.                 /*
  791.                  * Delay for a second so we don't flood the net!
  792.                  */
  793.                 while ( OTElapsedMilliseconds(&stamp) < 1000 )
  794.                 {
  795.                     if ( Button() )
  796.                         break;
  797.                 }
  798.             } while ( !Button() );
  799.             if ( err != kOTNoError )
  800.             {
  801.                 while ( Button() )
  802.                     ;
  803.                 break;
  804.             }
  805.  
  806.             fprintf(stderr, "Ready to Send.\n");
  807.         }
  808.         else
  809.         {
  810.             fprintf(stderr, "Size of replies to be sent: %d\n", kTestReplySize);
  811.             
  812.         }
  813.         
  814.         OTGetTimeStamp(&gStartStamp);
  815.         gTotalBytes    = 0;
  816.         
  817.         if ( gTestMode != 3 )
  818.         {
  819.             DoSendURequest(atpEp, gTestMode == 1 ? T_ACKNOWLEDGED : 0);
  820.         }
  821.         do
  822.         {
  823.             Boolean    needFlush = false;
  824.             if ( gDotCount >= 64 )
  825.             {
  826.                 gDotCount -= 64;
  827.                 gLineCount += 1;
  828.                 fprintf(stderr, ".");
  829.                 needFlush = true;
  830.             }
  831.             if ( gLineCount >= 64 )
  832.             {
  833.                 UInt32 milliSecs = OTElapsedMilliseconds(&gStartStamp);
  834.  
  835.                 gLineCount -= 64;
  836.                 fprintf(stderr, ": %lu\n", ((gTotalBytes * 1000)/milliSecs));
  837.                 gTotalBytes = 0;
  838.                 OTGetTimeStamp(&gStartStamp);
  839.             }
  840.             else if ( needFlush )
  841.                 fflush(stderr);
  842.         } while ( !Button() );                // Wait for 'um to press mouse button
  843.         
  844.         //
  845.         // Wait for the button to be unpressed
  846.         //
  847.         while ( Button() )
  848.             ;
  849.  
  850.         fflush(stderr);
  851.         //
  852.         // Cancel all outstanding commands
  853.         //
  854.         OTCancelURequest(atpEp, (OTSequence)0);
  855.         OTCancelUReply(atpEp, (OTSequence)0);
  856.         //
  857.         // Unbind
  858.         //
  859.         fprintf(stderr, "About to Unbind()\n");
  860.         gFunctionComplete = false;
  861.         err = OTUnbind(atpEp);
  862.         if ( err != kOTNoError )
  863.         {
  864.             fprintf(stderr, "ERROR: Unbind() returned %d\n", err);
  865.             break;
  866.         }
  867.         while ( !gFunctionComplete )
  868.             OTIdle();
  869.         if ( gFunctionEvent != T_UNBINDCOMPLETE )
  870.         {
  871.             fprintf(stderr, "OTUnbind: completed with event %08lX instead of %08lX\n",
  872.                     gFunctionEvent, T_UNBINDCOMPLETE);
  873.             break;
  874.         }
  875.     
  876.         if ( gFunctionErr != kOTNoError )
  877.         {
  878.             fprintf(stderr, "OTUnbind: completed with error %d\n", gFunctionErr);
  879.             break;
  880.         }
  881.  
  882.         ShowEndpointState(atpEp, "");
  883.         
  884.     } while (false);
  885.  
  886.  
  887.     //
  888.     // Get rid of endpoint.
  889.     //
  890.     if ( atpEp != kOTInvalidEndpointRef )
  891.         OTCloseProvider((ProviderRef)atpEp);
  892. }
  893.  
  894. /*******************************************************************************
  895. ** Initialize OpenTransport and call DoTest function
  896. ********************************************************************************/
  897.  
  898. main(int, char**) 
  899. {
  900.     InitGraf(&qd.thePort);                    // initialize quickdraw so we can use regions
  901.  
  902.     fprintf(stderr, "ATPSample showing usage of ATP.\n\n");
  903.     //
  904.     // Initialize Open Transport
  905.     //
  906.     InitOpenTransport();
  907.     //
  908.     // Run the test
  909.     //
  910.     DoTest();
  911.     //
  912.     // Close Open Transport.
  913.     // Not strictly necessary since it patches _ExitToShell and will
  914.     // clean us up anyway.
  915.     //
  916.     CloseOpenTransport();
  917.     
  918.     fprintf(stderr, "\n\nDone\n");
  919.     return 0;
  920. };
  921.  
  922.